package crack.transformer;

import org.objectweb.asm.*;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import static org.objectweb.asm.Opcodes.*;

public class CodeRemoverAgent implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        // 🔍 精确匹配目标类（请根据实际包路径调整！）
        if (!"com/fr/web/core/SessionPoolManager".equals(className)) {
            return null; // 不处理其他类
        }

        try {
            ClassReader cr = new ClassReader(classfileBuffer);
            ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
            ClassVisitor cv = new ClassVisitor(ASM7, cw) { // 建议用 ASM9
                @Override
                public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                    // ✅ 匹配带两个参数的目标方法
                    String targetName = "generateSessionID_checkPromptRegisted";
                    String targetDesc = "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V";

                    if (targetName.equals(name) && targetDesc.equals(descriptor)) {
                        System.out.println("[Agent] Replacing method body of SessionPoolManager.generateSessionID_checkPromptRegisted");

                        // ✅ 使用原始方法签名，确保兼容性
                        MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
                        injectYourBytecode(mv);
                        return null; // 跳过原方法体
                    }
                    return super.visitMethod(access, name, descriptor, signature, exceptions);
                }
            };

            cr.accept(cv, ClassReader.EXPAND_FRAMES);
            return cw.toByteArray();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private void injectYourBytecode(MethodVisitor mv) {
        mv.visitCode();

        Label label125 = new Label();
        Label label18 = new Label();
        Label afterIf = new Label();
        Label ifEq85 = new Label();
        Label ifEq102 = new Label();
        Label goto109 = new Label();

        // 0: iconst_1
        mv.visitInsn(ICONST_1);
        // 1: ifeq 125
        mv.visitJumpInsn(IFEQ, label125);

        // 4: System.currentTimeMillis()
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
        // 7: ldc2_w 10000000L
        mv.visitLdcInsn(10000000L);
        // 10: lcmp
        mv.visitInsn(LCMP);
        // 11: ifgt 18
        mv.visitJumpInsn(IFGT, label18);

        // 14: iconst_0
        mv.visitInsn(ICONST_0);
        mv.visitJumpInsn(GOTO, afterIf);

        // 18: iconst_1
        mv.visitLabel(label18);
        mv.visitInsn(ICONST_1);

        mv.visitLabel(afterIf);
        // 19: istore_2
        mv.visitVarInsn(ISTORE, 2);

        // 20: iload_2
        mv.visitVarInsn(ILOAD, 2);
        // 21: ifeq 125
        mv.visitJumpInsn(IFEQ, label125);

        // 24: new FRException
        mv.visitTypeInsn(NEW, "com/fr/stable/FRException");
        mv.visitInsn(DUP);
        mv.visitIntInsn(SIPUSH, 2102);
        mv.visitMethodInsn(INVOKESTATIC, "com/fr/locale/InterProviderFactory", "getProvider", "()Lcom/fr/locale/InterProvider;", false);
        mv.visitLdcInsn("Fine-Core_Base_Need_Purchase_Info");
        mv.visitMethodInsn(INVOKEINTERFACE, "com/fr/locale/InterProvider", "getLocText", "(Ljava/lang/String;)Ljava/lang/String;", true);
        mv.visitLdcInsn("Fine-Core_Base_Need_Purchase_Info");
        mv.visitMethodInsn(INVOKESPECIAL, "com/fr/stable/FRException", "<init>", "(ILjava/lang/String;Ljava/lang/String;)V", false);
        // 48: astore 4
        mv.visitVarInsn(ASTORE, 4);

        // 50: get PluginModule.ExtraCore
        mv.visitFieldInsn(GETSTATIC, "com/fr/plugin/injectable/PluginModule", "ExtraCore", "Lcom/fr/plugin/injectable/PluginModule;");
        mv.visitMethodInsn(INVOKESTATIC, "com/fr/plugin/injectable/PluginModule", "getAgent", "(Lcom/fr/plugin/injectable/PluginModule;)Ljava/lang/Object;", false);
        mv.visitTypeInsn(CHECKCAST, "com/fr/stable/plugin/ExtraClassManagerProvider");
        // 59: astore 5
        mv.visitVarInsn(ASTORE, 5);

        // 61: aconst_null
        mv.visitInsn(ACONST_NULL);
        // 62: astore 6
        mv.visitVarInsn(ASTORE, 6);

        // 64: aload 5
        mv.visitVarInsn(ALOAD, 5);
        // 66: aconst_null
        mv.visitInsn(ACONST_NULL);
        // 67: if_acmpeq 85
        mv.visitJumpInsn(IF_ACMPEQ, ifEq85);

        // 70: aload 5 → getSingle("UnregisteredPageProcessor")
        mv.visitVarInsn(ALOAD, 5);
        mv.visitLdcInsn("UnregisteredPageProcessor");
        mv.visitMethodInsn(INVOKEINTERFACE, "com/fr/stable/plugin/ExtraClassManagerProvider", "getSingle", "(Ljava/lang/String;)Lcom/fr/stable/fun/mark/Immutable;", true);
        mv.visitTypeInsn(CHECKCAST, "com/fr/stable/fun/UnregisteredPageProcessor");
        // 83: astore 6
        mv.visitVarInsn(ASTORE, 6);

        mv.visitLabel(ifEq85);
        // 85: aload 6
        mv.visitVarInsn(ALOAD, 6);
        // 87: aconst_null
        mv.visitInsn(ACONST_NULL);
        // 88: if_acmpeq 102
        mv.visitJumpInsn(IF_ACMPEQ, ifEq102);

        // 91: createWeblet()
        mv.visitVarInsn(ALOAD, 6);
        mv.visitMethodInsn(INVOKEINTERFACE, "com/fr/stable/fun/UnregisteredPageProcessor", "createWeblet", "()Lcom/fr/stable/web/Weblet;", true);
        // 98: astore_3
        mv.visitVarInsn(ASTORE, 3);
        mv.visitJumpInsn(GOTO, goto109);

        mv.visitLabel(ifEq102);
        // 102: WebletFactory.createEmbeddedWeblet("/com/fr/web/tpl/lic.frm")
        mv.visitLdcInsn("/com/fr/web/tpl/lic.frm");
        mv.visitMethodInsn(INVOKESTATIC, "com/fr/web/factory/WebletFactory", "createEmbeddedWeblet", "(Ljava/lang/String;)Lcom/fr/stable/web/Weblet;", false);
        // 108: astore_3
        mv.visitVarInsn(ASTORE, 3);

        mv.visitLabel(goto109);
        // 109: setHandlerMethod and throw
        mv.visitVarInsn(ALOAD, 4); // FRException
        mv.visitTypeInsn(NEW, "com/fr/web/core/DefaultHandlerMethod");
        mv.visitInsn(DUP);
        mv.visitVarInsn(ALOAD, 3); // Weblet
        mv.visitMethodInsn(INVOKESPECIAL, "com/fr/web/core/DefaultHandlerMethod", "<init>", "(Lcom/fr/stable/web/Weblet;)V", false);
        mv.visitMethodInsn(INVOKEVIRTUAL, "com/fr/stable/FRException", "setHandlerMethod", "(Lcom/fr/stable/HandlerMethod;)V", false);
        mv.visitVarInsn(ALOAD, 4);
        mv.visitInsn(ATHROW);

        mv.visitLabel(label125);
        // 125: return
        mv.visitInsn(RETURN);

        mv.visitMaxs(0, 0); // auto-computed by COMPUTE_MAXS
        mv.visitEnd();
    }
}